import sys
sys.path.append(sys.path[0] + "/../interpreter")
sys.path.append(sys.path[0] + "/ply-2.5/")
from functionBinding import functionBinding
from functionDef import functionDef
from application import application
from Return import Return
from builtin import *
from varRef import varRef
from jsobject import *
from interpreter import interpreter
from endvals import *
from objectOps import *
from sequence import *
from conditionals import *
from sequence import *
from varBinding import *
from varMut import *
from customExceptions import *
from scope import *

import ply.yacc as yacc 



scopecount = 0
#---------------------------------------------------------------------------------------------

reserved = {
   'if' : 'IF',
   'else' : 'ELSE',
   'while' : 'WHILE',
   'void' : 'VOID',
   'new' : 'NEW',
   'var' : 'VAR',
   'return' : 'RETURN',
   'function': 'FUN'
   
}



tokens = ['STRING','BOOL', 'FLOAT','INT', 'PLUS','MINUS','TIMES','DIVIDE','EQUALS', 'LPAREN','RPAREN','LBRACK', 'RBRACK',  'ID',  'END', 'DOT', 'EQEQ', 'COMMA', 'LESSTHAN' , 'GREATERTHAN', 'LESSEQ', 'GREATEREQ', 'AND', 'NOT', 'OR'] + reserved.values() 

# Tokens





t_PLUS = r'\+' 
t_MINUS = r'-' 
t_TIMES = r'\*' 
t_DIVIDE = r'/' 
t_EQUALS = r'=' 
t_LPAREN = r'\(' 
t_RPAREN = r'\)' 
t_LBRACK = r'\{'
t_RBRACK = r'\}'
t_EQEQ = r'=='
t_END = r';'
t_DOT = r'\.'
t_COMMA = r','
t_LESSTHAN = r'<'
t_GREATERTHAN = r'>'
t_LESSEQ = r'<='
t_GREATEREQ = r'>='
t_AND = r'&&'
t_OR = r'\|\|'
t_NOT = r'!'

special = ["strlen", "substr", "strEq" , "strLess" , "equals" , "intQ" , "boolQ" , "floatQ" , "voidQ" , "stringQ" , "instanceOf" ,
				"closureQ" , "plainQ" , "printOut" , "readLine"]

def t_STRING(t):
	r'\"[^ \t\n\r\f\v\"]*\"'
	return t

def t_BOOL(t): 
	r'true|false' 
	try: 
		if(t.value == 'false'):
			t.value = False
		else:
			t.value = True

	except ValueError: 
		print "Boolean value too large", t.value 
		t.value = 0 
	return t

def t_FLOAT(t): 
	r'[0-9]*\.[0-9]+' 
	try:
		t.value = float(t.value) 

	except ValueError: 
		print "Float value too large", t.value 
		t.value = 0 
	return t

def t_INT(t): 
	r'\d+' 
	try: t.value = int(t.value) 
	except ValueError: 
		print "Integer value too large", t.value 
		t.value = 0 
	return t

def t_ID(t):
    r'[a-zA-Z_][a-zA-Z_0-9\?\-\<\=]*'
    t.type = reserved.get(t.value,'ID')    # Check for reserved words
    return t


# Ignored characters 
def t_whitespace(t):
	r'\s+' 
	pass

def t_newline(t): 
	r'\n+' 
	t.lexer.lineno += t.value.count("\n")

def t_error(t):
	print "Illegal character '%s'" % t.value[0] 
	t.lexer.skip(1) 


import ply.lex as lex
lex.lex()

#lex.input("function bird (x,y) {x + y};")
#print lex.token();




#---------------------------------------------------------------------------------------------
# add all rules below this line and...

precedence = (
    ('left', 'EQEQ'),
    ('left', 'AND', 'OR'),
    ('left', 'GREATERTHAN','GREATEREQ','LESSTHAN','LESSEQ'),
    ('left', 'DIVIDE'),
    ('left', 'PLUS', 'MINUS'),
    ('left', 'TIMES'),
    ('left', 'NOT'),
    ('left', 'DOT'),
)

# this rule should get replaced at some point (I think...)
def p_stmt(p):
	'''stmt : expr END
		| ID EQUALS expr END
		| expr DOT ID EQUALS expr END
		| RETURN expr END
		| IF LPAREN expr RPAREN LBRACK sequence RBRACK ELSE LBRACK sequence RBRACK 
		| IF LPAREN expr RPAREN LBRACK sequence RBRACK 
		| WHILE LPAREN expr RPAREN LBRACK sequence RBRACK'''


	if(len(p) > 9 and p[1] == "if" and p[8] == "else"):
		#print "TEST: ",p[3]," THEN: ",p[6], " ELSE: ", p[10]
		p[0] = ifthen(p[3],scope(sequence(p[6])) ,scope(sequence(p[10])))
	elif(p[1] == "if" and len(p) < 9):
		#print "TEST: ",p[3]," THEN: ",p[6]
		p[0] = ifthen(p[3], scope(sequence(p[6])),sequence([]))
	elif(p[2] == "="):
		p[0] = varMut(p[1] + "_u",p[3])
	elif(p[2] == "."):
		p[0] = fieldMutation(p[1],p[3] + "_u",p[5])
	elif(p[1] == "return"):
		p[0] = Return(p[2])
	elif(p[1] == "while"):
		p[0] = whileloop(p[3], scope(sequence(p[6])))
	elif(p[2] == ";"):
		p[0] = p[1]

#	print "Interped: ", str(p[0])
	#print "HERE"
	#x = 0
	#while(x < len(p)):
	#	print p[x]
	#	x+=1	
	p[0]
	

def p_function_bind(p):
	'''stmt : FUN fundef
		   		| FUN fundef stmt'''
	if(len(p) > 3):
		#print "functions: ",str(p[2]), " Body: ", str(p[3])
		p[0] = functionBinding(p[2],p[3])
	else:
		p[0] = functionBinding(p[2], void())

#def p_set_seq(p):
#	'''set : sequence''' 
#	print 'Try this: ' , p[1]
#	p[0] = sequence(p[1])

def p_var_bind(p):
	'''stmt : VAR ID EQUALS expr END 
		 			| VAR ID EQUALS expr END sequence'''  
	if(len(p) > 6):
		#print "Body: ", p[6]
		p[0] = varBinding(p[2] + "_u",p[4],sequence(p[6]))
	else:
		p[0] = varBinding(p[2] + "_u",p[4],void())

def p_func(p):
	'''fundef : ID LPAREN paramlist RPAREN LBRACK sequence RBRACK FUN fundef
			| ID LPAREN paramlist RPAREN LBRACK sequence RBRACK'''
	if(len(p) > 8):
		temp = [functionDef(p[1] + "_u",p[3],scope(sequence(p[6])))]
		temp.extend(p[9])
		p[0] = temp
	else:
		p[0] = [functionDef(p[1]+ "_u",p[3],scope(sequence(p[6])))]


def p_param_list(p):
	'''paramlist : ID COMMA paramlist
			| ID
			| empty'''
	if(len(p) > 2):
		temp = [p[1] + "_u"]
		temp.extend(p[3])
		p[0] = temp
	else:
		if(p[1] == None):
			p[0] = [p[1]]
		else:
			p[0] = [p[1] + "_u"]

def p_sequence(p):
	'''sequence : stmt sequence 
		    | stmt 
		    | empty'''
	if(len(p) > 2):
		temp = [p[1]]
		temp.extend(p[2])
		p[0] = temp
	else:
		p[0] = [p[1]]


def p_expr(p):
	'''expr :  expr PLUS expr
  			| expr TIMES expr
			| expr DIVIDE expr
			| expr MINUS expr 
			| LPAREN expr RPAREN
			| expr AND expr
			| expr OR expr
			| NOT expr
			| expr LESSTHAN expr
			| expr GREATERTHAN expr
			| expr LESSEQ expr
			| expr GREATEREQ expr
			| expr EQEQ expr'''
	#x = 0
	#while(x < len(p)):
	#	print p[x]
	#	x+=1	

	if(p[1] == "(" and p[3] == ")"):
		p[0] = p[2]
	elif(p[1] == "!"):
		p[0] = application("not", [p[2]])
	elif(p[2] == "&&"):
		p[0] = application("and", [p[1], p[3]])
	elif(p[2] == "||"):
		p[0] = application("or", [p[1], p[3]])
	elif(p[2] == "+"):
		p[0] = application("plus", [p[1], p[3]])
	elif(p[2] == "-"):
		p[0] = application("minus", [p[1], p[3]])
	elif(p[2] == "*"):
		p[0] = application("mult", [p[1], p[3]])
	elif(p[2] == "<"):
		p[0] = application("lessThan", [p[1], p[3]])
	elif(p[2] == ">"):
		p[0] = application("greatThan", [p[1], p[3]])
	elif(p[2] == "<="):
		p[0] = application("lessEq", [p[1], p[3]])
	elif(p[2] == ">="):
		p[0] = application("greatEq", [p[1], p[3]])
	elif(p[2] == "=="):
		p[0] = application("equals", [p[1], p[3]])
	elif(len(p) == 4):
		p[0] = application(p[2] + "_u", [p[1], p[3]])
	#	if(p[2] == '+' or p[2] == '-' or p[2] == '*' or p[2] == '/'):
	#			print "Printing the llvm: " + p[0].translate()

	else:
		print "Not an Expression"

def p_expr_methodCall(p):
	'''expr : expr DOT ID LPAREN arglist RPAREN'''
	#if(len(p) > 4):
		#print "HERE"
	p[0] = methodCall(p[1],p[3] + "_u",p[5])
	#else:
	#	p[0] = fieldLookup(p[1],p[3] + "_u")


def p_expr_field(p):
	'''expr : expr DOT ID'''
	p[0] = fieldLookup(p[1],p[3] + "_u")

def p_expr_new(p):
	'''expr : NEW ID LPAREN arglist RPAREN'''
	#print "*************************Name: ",p[2]," Args: ",p[4]
	p[0] = new(varRef(p[2] + "_u"),p[4])



def p_expr_idargs(p):
	'''expr : ID LPAREN arglist RPAREN'''
	#print "Name: ",p[1]," Args: ",p[3]
	if(p[1] == "!"):
		p[0] = application("not", p[3])
	elif(p[1] == "&&"):
		p[0] = application("and", p[3])
	elif(p[1] == "||"):
		p[0] = application("or", p[3])
	elif(p[1] == "+"):
		p[0] = application("plus", p[3])
	elif(p[1] == "-"):
		p[0] = application("minus", p[3])
	elif(p[1] == "*"):
		p[0] = application("mult", p[3])
	elif(p[1] == "<"):
		p[0] = application("lessThan", p[3])
	elif(p[1] == ">"):
		p[0] = application("greatThan", p[3])
	elif(p[1] == "<="):
		p[0] = application("lessEq", p[3])
	elif(p[1] == ">="):
		p[0] = application("greatEq", p[3])
	elif(p[1] == "=="):
		p[0] = application("equals", p[3])
	elif(p[1] == "substring"):
		p[0] = application("substr",p[3])
	elif(p[1] == "integer?"):
		p[0] = application("intQ",p[3])
	elif(p[1] == "boolean?"):
		p[0] = application("boolQ",p[3])
	elif(p[1] == "floating-point?"):
		p[0] = application("floatQ",p[3])
	elif(p[1] == "void?"):
		p[0] = application("voidQ",p[3])
	elif(p[1] == "string?"):
		p[0] = application("stringQ",p[3])
	elif(p[1] == "instanceof"):
		p[0] = application("instanceof",p[3])
	elif(p[1] == "closure?"):
		p[0] = application("closureQ",p[3])
	elif(p[1] == "plain?"):
		p[0] = application("plainQ",p[3])
	elif(p[1] == "print"):
		p[0] = application("printOut",p[3])
	elif(p[1] == "read-line"):
		p[0] = application("readLine",p[3])
	elif(p[1] == "string-length"):
		p[0] = application("strlen",p[3])
	elif(p[1] == "string<?"):
		p[0] = application("strLess",p[3])
	elif(p[1] == "string=?"):
		p[0] = application("strEq",p[3])
		print "HERE: " + str(p[3]) + "\n"
	else:
		p[0] = application(p[1]+"_u",p[3])

def p_expr_idargsp(p):
	'''expr : ID LPAREN RPAREN'''
	#print "Name: ",p[1]
	if(p[1] == "!"):
		p[0] = application("not", [])
	elif(p[1] == "&&"):
		p[0] = application("and", [])
	elif(p[1] == "||"):
		p[0] = application("or", [])
	elif(p[1] == "+"):
		p[0] = application("plus", [])
	elif(p[1] == "-"):
		p[0] = application("minus", [])
	elif(p[1] == "*"):
		p[0] = application("mult", [])
	elif(p[1] == "<"):
		p[0] = application("lessThan", [])
	elif(p[1] == ">"):
		p[0] = application("greatThan", [])
	elif(p[1] == "<="):
		p[0] = application("lessEq", [])
	elif(p[1] == ">="):
		p[0] = application("greatEq", [])
	elif(p[1] == "=="):
		p[0] = application("equals", [])
	elif(p[1] == "string-length"):
		p[0] = application("strlen",[])
	elif(p[1] == "substring"):
		p[0] = application("substr",[])
	elif(p[1] == "string=?"):
		p[0] = application("strEq",[])
	elif(p[1] == "string<?"):
		p[0] = application("strLess",[])
	elif(p[1] == "integer?"):
		p[0] = application("intQ",[])
	elif(p[1] == "boolean?"):
		p[0] = application("boolQ",[])
	elif(p[1] == "floating-point?"):
		p[0] = application("floatQ",[])
	elif(p[1] == "void?"):
		p[0] = application("voidQ",[])
	elif(p[1] == "string?"):
		p[0] = application("stringQ",[])
	elif(p[1] == "instanceof"):
		p[0] = application("instanceof",[])
	elif(p[1] == "closure?"):
		p[0] = application("closureQ",[])
	elif(p[1] == "plain?"):
		p[0] = application("plainQ",[])
	elif(p[1] == "print"):
		p[0] = application("printOut",[])
	elif(p[1] == "read-line"):
		p[0] = application("readLine",[])
	else:
		p[0] = application(p[1] +"_u",[])

def p_expr_app(p):
	'''expr : LPAREN expr RPAREN LPAREN arglist RPAREN'''
	p[0] = application(p[2] + "_u",p[5])




def p_expr_str(p):
	'''expr : STRING'''
	p[1] = p[1][1:]
	p[1] = p[1][:-1]
	p[0] = stringval(p[1])

def p_expr_arglist(p):
	'''arglist : expr COMMA arglist
			| expr
			| empty'''
	#print "ARGS : " , p[1]
	if(len(p) > 2):
		temp = [p[1]]
		temp.extend(p[3])
		p[0] = temp
	else:
		p[0] = [p[1]]







def p_expr_id(p):
	'''expr : ID'''
	if(p[1] != "this"):
		p[0] = varRef(p[1] + "_u")
	else:
		p[0] = varRef(p[1])	

def p_expr_ints(p):
	'''expr : INT'''
	p[0] = integer(p[1])

def p_expr_floats(p):
	'''expr : FLOAT'''
	p[0] = flp(p[1])

def p_expr_bools(p):
	'''expr : BOOL'''
	p[0] = boolean(p[1])

def p_expr_voids(p):
	'''expr : VOID'''
	p[0] = void()



def p_empty(p):
    'empty :'
    pass

def p_error(p):
	print "syntax error!\n"

class parserClass:
	def __init__(self, string):
		self.parser = yacc.yacc()
		self.myString = string
	
	def parse(self):
		#add the scope over the whole AST
		return scope(self.parser.parse(self.myString))
		

if __name__ == '__main__':
	while 1: 
		try: 
			temp = parserClass(raw_input('% > '))
		except EOFError: 
			break 
		var = temp.parse()
		print "Interpreted: ", interpreter(var)
		print "Returned: ", str(var)




